package com.example.front.service.impl;

import com.alipay.api.AlipayResponse;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.demo.trade.config.Configs;
import com.alipay.demo.trade.model.ExtendParams;
import com.alipay.demo.trade.model.GoodsDetail;
import com.alipay.demo.trade.model.builder.AlipayTradePrecreateRequestBuilder;
import com.alipay.demo.trade.model.result.AlipayF2FPrecreateResult;
import com.alipay.demo.trade.service.AlipayTradeService;
import com.alipay.demo.trade.service.impl.AlipayTradeServiceImpl;
import com.alipay.demo.trade.utils.ZxingUtils;
import com.example.front.dao.*;
import com.example.front.service.IOrderService;
import com.example.front.vo.OrderItemVo;
import com.example.front.vo.OrderProductVo;
import com.example.front.vo.OrderVo;
import com.example.front.vo.ShippingVo;
import com.example.gok_mall.constUtil.ConstUtil;
import com.example.gok_mall.constUtil.DateTimeUtil;
import com.example.gok_mall.constUtil.FTPUtil;
import com.example.gok_mall.entity.*;
import com.example.gok_mall.reponseData.ResultData;
import com.example.gok_mall.util.BigDecimalUtil;
import com.example.gok_mall.util.PropertiesUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;

@Slf4j
@Service
public class OrderServiceImpl implements IOrderService {

    @Autowired
    private OrderDao orderDao;

    @Autowired
    private OrderItemDao orderItemDao;

    @Autowired
    private PayInfoDao payInfoDao;

    @Autowired
    private CartDao cartDao;

    @Autowired
    private ProductDao productDao;

    @Autowired
    private ShippingDao shippingDao;

    //创建订单接口的实现
    @Override
    public ResultData createOrder(Integer userId, Integer shippingId) {
        //从购物车中获取数据
        List<Cart> cartList = cartDao.selectCheckedCartByUserId(userId);
        //计算这个订单的总价
        ResultData resultData = this.getCartOrderItem(userId, cartList);
        if (!resultData.isSuccess()) {
            return resultData;
        }
        List<OrderItem> orderItemList = (List<OrderItem>) resultData.getData();
        BigDecimal payment = this.getOrderTotalPrice(orderItemList);

        //生成订单
        Order order = this.assembleOrder(userId, shippingId, payment);
        if (order == null) {
            return ResultData.fail("生成订单错误");
        }
        if (CollectionUtils.isEmpty(orderItemList)) {
            return ResultData.fail("购物车为空");
        }
        for (OrderItem orderItem : orderItemList) {
            orderItem.setOrderNo(order.getOrderNo());
        }

        //mybatis 批量插入
        orderItemDao.batchInsert(orderItemList);

        //生成成功，减少库存
        this.reduceProductStock(orderItemList);

        //清除购物车
        this.cleanCart(cartList);

        //返回数据给前端
        OrderVo orderVo = assembleOrderVo(order, orderItemList);
        return ResultData.createData(orderVo);

    }

    //组装返回给前端的数据
    private OrderVo assembleOrderVo(Order order, List<OrderItem> orderItemList) {
        OrderVo orderVo = new OrderVo();
        orderVo.setOrderNo(order.getOrderNo());
        orderVo.setPayment(order.getPayment());
        orderVo.setPaymentType(order.getPaymentType());
        orderVo.setPaymentTypeDesc(ConstUtil.PaymentTypeEnum.codeOf(order.getPaymentType()).getValue());
        orderVo.setPostage(order.getPostage());
        orderVo.setStatus(order.getStatus());
        orderVo.setStatusDesc(ConstUtil.OrderStatusEnum.codeOf(order.getStatus()).getValue());

        orderVo.setShippingId(order.getShippingId());
        Shipping shipping = shippingDao.selectByPrimaryKey(order.getShippingId());
        if (shipping != null) {
            orderVo.setReceiverName(shipping.getReceiverName());
            orderVo.setShippingVo(assembleShippingVo(shipping));
        }

        orderVo.setPaymentTime(DateTimeUtil.dateToStr(order.getPaymentTime()));
        orderVo.setSendTime(DateTimeUtil.dateToStr(order.getSendTime()));
        orderVo.setEndTime(DateTimeUtil.dateToStr(order.getEndTime()));
        orderVo.setCreateTime(DateTimeUtil.dateToStr(order.getCreateTime()));
        orderVo.setCloseTime(DateTimeUtil.dateToStr(order.getCloseTime()));

        //orderVo.setImageHost(PropertiesUtil.getProperty("ftp.server.http.prefix"));

        List<OrderItemVo> orderItemVoList = Lists.newArrayList();
        for (OrderItem orderItem : orderItemList) {
            OrderItemVo orderItemVo = assembleOrderItemVo(orderItem);
            orderItemVoList.add(orderItemVo);
        }

        orderVo.setOrderItemVoList(orderItemVoList);

        return orderVo;
    }

    //将订单详情orderItem中的数据组合到orderItemVo中
    private OrderItemVo assembleOrderItemVo(OrderItem orderItem) {
        OrderItemVo orderItemVo = new OrderItemVo();
        orderItemVo.setOrderNo(orderItem.getOrderNo());
        orderItemVo.setProductId(orderItem.getProductId());
        orderItemVo.setProductName(orderItem.getProductName());
        orderItemVo.setProductImage(orderItem.getProductImage());
        orderItemVo.setCurrentUnitPrice(orderItem.getCurrentUnitPrice());
        orderItemVo.setQuantity(orderItem.getQuantity());
        orderItemVo.setTotalPrice(orderItem.getTotalPrice());

        orderItemVo.setCreateTime(DateTimeUtil.dateToStr(orderItem.getCreateTime()));
        return orderItemVo;
    }

    //将shipping中的数据装到ShippingVo里面
    private ShippingVo assembleShippingVo(Shipping shipping) {
        ShippingVo shippingVo = new ShippingVo();
        shippingVo.setReceiverName(shipping.getReceiverName());
        shippingVo.setReceiverAddress(shipping.getReceiverAddress());
        shippingVo.setReceiverProvince(shipping.getReceiverProvince());
        shippingVo.setReceiverCity(shipping.getReceiverCity());
        shippingVo.setReceiverDistrict(shipping.getReceiverDistrict());
        shippingVo.setReceiverMobile(shipping.getReceiverMobile());
        shippingVo.setReceiverPhone(shipping.getReceiverPhone());
        shippingVo.setReceiverZip(shipping.getReceiverZip());
        return shippingVo;
    }

    //清除购物车方法
    private void cleanCart(List<Cart> cartList) {
        for (Cart cartItem : cartList) {
            cartDao.deleteByPrimaryKey(cartItem.getId());

        }
    }


    //更新库存的方法
    private void reduceProductStock(List<OrderItem> orderItemList) {
        for (OrderItem orderItem : orderItemList) {
            Product product = productDao.selectByPrimaryKey(orderItem.getProductId());
            product.setStock(product.getStock() - orderItem.getQuantity());
            productDao.updateByPrimaryKeySelective(product);
        }
    }


    //组装订单信息（所要下单的订单的信息）payment:支付总金额
    private Order assembleOrder(Integer userId, Integer shippingId, BigDecimal payment) {

        Order order = new Order();
        long orderNo = this.generateOrderNo();
        order.setOrderNo(orderNo);
        order.setStatus(ConstUtil.OrderStatusEnum.NO_PAY.getCode());
        order.setPostage(0);
        order.setPaymentType(ConstUtil.PaymentTypeEnum.ONLINE_PAY.getCode());
        order.setPayment(payment);
        order.setUserId(userId);
        order.setShippingId(shippingId);

        //发货时间
        //付款时间
        int rowCount = orderDao.insert(order);
        if (rowCount > 0) {
            return order;
        }
        return null;
    }


    //生成订单号，利用时间戳和随机数
    private long generateOrderNo() {
        long currentTime = System.currentTimeMillis();
        return currentTime + new Random().nextInt(100);
    }


    //获取订单的总价格
    private BigDecimal getOrderTotalPrice(List<OrderItem> orderItemList) {
        BigDecimal payment = new BigDecimal("0");
        for (OrderItem orderItem : orderItemList) {
            payment = BigDecimalUtil.add(payment.doubleValue(), orderItem.getTotalPrice().doubleValue());
        }
        return payment;
    }


    //获取购物车中订单的信息
    private ResultData getCartOrderItem(Integer userId, List<Cart> cartList) {
        List<OrderItem> orderItemList = Lists.newArrayList();
        if (CollectionUtils.isEmpty(cartList)) {
            return ResultData.fail("购物车为空");
        }

        //校验购物车中的数据，包括产品的数量和状态
        for (Cart cartItem : cartList) {
            OrderItem orderItem = new OrderItem();
            System.out.println("ProductId: " + cartItem.getProductId());
            Product product = productDao.selectByPrimaryKey(cartItem.getProductId());

            if (product == null) {
                System.out.println("空指针异常");
            }


            if (ConstUtil.ProductStatusEnum.ON_SALE.getCode() != product.getStatus()) {
                return ResultData.createData("产品" + product.getName() + "不是在线售卖状态");
            }

            //校验库存
            if (cartItem.getQuantity() > product.getStock()) {
                return ResultData.createData("产品" + product.getName() + "库存不足");
            }

            //设置单一商品的相关信息
            orderItem.setUserId(userId);
            orderItem.setProductId(product.getId());
            orderItem.setProductName(product.getName());
            orderItem.setProductImage(product.getMainImage());
            orderItem.setCurrentUnitPrice(product.getPrice());
            orderItem.setQuantity(cartItem.getQuantity());
            orderItem.setTotalPrice(BigDecimalUtil.mul(product.getPrice().doubleValue(), cartItem.getQuantity()));


            //分别将每个商品的订单信息添加到orderItemList这个List数组里面
            orderItemList.add(orderItem);
        }
        return ResultData.createData(orderItemList);
    }


    //取消订单接口的开发
    @Override
    public ResultData<String> cancel(Integer userId, Long orderNo) {
        Order order = orderDao.selectByUserIdAndOrderNo(userId, orderNo);
        if (order == null) {
            return ResultData.fail("该用户没有此订单");
        }
        if (order.getStatus() != ConstUtil.OrderStatusEnum.NO_PAY.getCode()) {
            return ResultData.fail("已付款，该订单无法取消");
        }
        Order updateOrder = new Order();
        updateOrder.setId(order.getId());
        updateOrder.setStatus(ConstUtil.OrderStatusEnum.CANCELED.getCode());

        int row = orderDao.updateByPrimaryKeySelective(updateOrder);
        if (row > 0) {
            return ResultData.success();
        }
        return ResultData.fail("失败");

    }

    //获取购物车接口 (已经选中打算结算的购物车中商品的信息接口)
    @Override
    public ResultData getOrderCartProduct(Integer userId) {
        OrderProductVo orderProductVo = new OrderProductVo();
        //从购物车中获取数据
        List<Cart> cartList = cartDao.selectCartByUserId(userId);
//        System.out.println("cartList:"+cartList);
        ResultData resultData = this.getCartOrderItem(userId, cartList);
        if (!resultData.isSuccess()) {
            return resultData;
        }

        List<OrderItem> orderItemList = (List<OrderItem>) resultData.getData();

        List<OrderItemVo> orderItemVoList = Lists.newArrayList();

        BigDecimal payment = new BigDecimal("0");
        for (OrderItem orderItem : orderItemList) {
            payment = BigDecimalUtil.add(payment.doubleValue(), orderItem.getTotalPrice().doubleValue());
            orderItemVoList.add(assembleOrderItemVo(orderItem));
        }

        orderProductVo.setProductTotalPrice(payment);
        //orderProductVo.setImageHost(PropertiesUtil.getProperty("ftp.server.http.prefix"));
        orderProductVo.setOrderItemVoList(orderItemVoList);
        return ResultData.createData(orderProductVo);
    }

    //查询订单详情的接口实现
    @Override
    public ResultData<OrderVo> getOrderDetail(Integer userId, Long orderNo) {
        Order order = orderDao.selectByUserIdAndOrderNo(userId, orderNo);
        if (order != null) {
            List<OrderItem> orderItemList = orderItemDao.getByOrderNoUserId(orderNo, userId);
            OrderVo orderVo = assembleOrderVo(order, orderItemList);
            return ResultData.createData(orderVo);
        }
        return ResultData.fail("没有找到该订单");
    }

    //个人中心查看订单列表接口
    @Override
    public ResultData<PageInfo> getOrderList(Integer userId, int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<Order> orderList = orderDao.getOrderListByUserId(userId);

        List<OrderVo> orderVoList = assembleOrderVoList(orderList, userId);

        PageInfo pageResult = new PageInfo(orderList);
        pageResult.setList(orderVoList);
        return ResultData.createData(pageResult);
    }

    @Override
    public ResultData<PageInfo> manageList(int pageNum, int pageSize) {
        return null;
    }

    @Override
    public ResultData<OrderVo> manageDetail(Long orderNo) {
        return null;
    }

    @Override
    public ResultData<PageInfo> manageSearch(Long orderNo, int pageNum, int pageSize) {
        return null;
    }

    @Override
    public ResultData<String> manageSendGoods(Long orderNo) {
        return null;
    }

    //封装一个组装用户订单详情的私有方法
    private List<OrderVo> assembleOrderVoList(List<Order> orderList, Integer userId) {
        List<OrderVo> orderVoList = Lists.newArrayList();
        for (Order order : orderList) {
            List<OrderItem> orderItemList = Lists.newArrayList();
            if (userId == null) {
                //TODO  以管理员的身份去查看订单列表，不需要传userId，因为管理员可以查看每个人的订单
                orderItemList = orderItemDao.getAllByOrderNo(order.getOrderNo());
            } else {
                orderItemList = orderItemDao.getByOrderNoUserId(order.getOrderNo(), userId);
            }
            OrderVo orderVo = assembleOrderVo(order, orderItemList);
            orderVoList.add(orderVo);
        }
        return orderVoList;
    }

    //支付接口的实现
    @Override
    public ResultData pay(Long orderNo,Integer userId,String path){
        Map<String, String> resultMap= Maps.newHashMap();
            Order order = orderDao.selectByUserIdAndOrderNo(userId,orderNo);

        if(order == null){
            return ResultData.fail("用户没有该订单");
        }
        resultMap.put("orderNo",String.valueOf(order.getOrderNo()));
            // (必填) 商户网站订单系统中唯一订单号，64个字符以内，只能包含字母、数字、下划线，
            // 需保证商户系统端不能重复，建议通过数据库sequence生成，
            String outTradeNo = order.getOrderNo().toString();

            // (必填) 订单标题，粗略描述用户的支付目的。如“xxx品牌xxx门店当面付扫码消费”
            String subject = new StringBuilder().append("happymmall扫码支付").append(outTradeNo).toString();

            // (必填) 订单总金额，单位为元，不能超过1亿元
            // 如果同时传入了【打折金额】,【不可打折金额】,【订单总金额】三者,则必须满足如下条件:【订单总金额】=【打折金额】+【不可打折金额】
            String totalAmount = order.getPayment().toString();

            // (可选) 订单不可打折金额，可以配合商家平台配置折扣活动，如果酒水不参与打折，则将对应金额填写至此字段
            // 如果该值未传入,但传入了【订单总金额】,【打折金额】,则该值默认为【订单总金额】-【打折金额】
            String undiscountableAmount = "0";

            // 卖家支付宝账号ID，用于支持一个签约账号下支持打款到不同的收款账号，(打款到sellerId对应的支付宝账号)
            // 如果该字段为空，则默认为与支付宝签约的商户的PID，也就是appid对应的PID
            String sellerId = "";

            // 订单描述，可以对交易或商品进行一个详细地描述，比如填写"购买商品2件共15.00元"
            String body = new StringBuilder().append("订单").append(outTradeNo).append("购买商品共").append(totalAmount).append("元").toString();

            // 商户操作员编号，添加此参数可以为商户操作员做销售统计
            String operatorId = "test_operator_id";

            // (必填) 商户门店编号，通过门店号和商家后台可以配置精准到门店的折扣信息，详询支付宝技术支持
            String storeId = "test_store_id";

            // 业务扩展参数，目前可添加由支付宝分配的系统商编号(通过setSysServiceProviderId方法)，详情请咨询支付宝技术支持
            ExtendParams extendParams = new ExtendParams();
            extendParams.setSysServiceProviderId("2088100200300400500");

            // 支付超时，定义为120分钟
            String timeoutExpress = "120m";

            // 商品明细列表，需填写购买商品详细信息，
            List<GoodsDetail> goodsDetailList = new ArrayList<GoodsDetail>();

            List<OrderItem> orderItemList= orderItemDao.getByOrderNoUserId(orderNo,userId);
            for (OrderItem orderItem : orderItemList){
                // 创建一个商品信息，参数含义分别为商品id（使用国标）、名称、单价（单位为分）、数量，如果需要添加商品类别，详见GoodsDetail
                GoodsDetail goods = GoodsDetail.newInstance(orderItem.getProductId().toString(), orderItem.getProductName(),
                        BigDecimalUtil.mul(orderItem.getCurrentUnitPrice().doubleValue(),
                        new Double(100).doubleValue()).longValue(), orderItem.getQuantity());
                // 创建好一个商品后添加至商品明细列表
                goodsDetailList.add(goods);
            }

//            // 创建一个商品信息，参数含义分别为商品id（使用国标）、名称、单价（单位为分）、数量，如果需要添加商品类别，详见GoodsDetail
//            GoodsDetail goods1 = GoodsDetail.newInstance("goods_id001", "xxx小面包", 1000, 1);
//            // 创建好一个商品后添加至商品明细列表
//            goodsDetailList.add(goods1);


            // 继续创建并添加第一条商品信息，用户购买的产品为“黑人牙刷”，单价为5.00元，购买了两件
//            GoodsDetail goods2 = GoodsDetail.newInstance("goods_id002", "xxx牙刷", 500, 2);
//            goodsDetailList.add(goods2);

            // 创建扫码支付请求builder，设置请求参数
            AlipayTradePrecreateRequestBuilder builder = new AlipayTradePrecreateRequestBuilder()
                    .setSubject(subject).setTotalAmount(totalAmount).setOutTradeNo(outTradeNo)
                    .setUndiscountableAmount(undiscountableAmount).setSellerId(sellerId).setBody(body)
                    .setOperatorId(operatorId).setStoreId(storeId).setExtendParams(extendParams)
                    .setTimeoutExpress(timeoutExpress)
                    .setNotifyUrl(PropertiesUtil.getProperty("alipay.callback.url"))
                    //支付宝服务器主动通知商户服务器里指定的页面http路径,根据需要设置
                    //.setNotifyUrl("http://kxkc7h.natappfree.cc/order/alipay_callback.do")
                    .setGoodsDetailList(goodsDetailList);


        /** 一定要在创建AlipayTradeService之前调用Configs.init()设置默认参数
         *  Configs会读取classpath下的zfbinfo.properties文件配置信息，如果找不到该文件则确认该文件是否在classpath目录
         */
        Configs.init("zfbinfo.properties");

        /** 使用Configs提供的默认参数
         *  AlipayTradeService可以使用单例或者为静态成员对象，不需要反复new
         */
        AlipayTradeService tradeService = new AlipayTradeServiceImpl.ClientBuilder().build();

        AlipayF2FPrecreateResult result = tradeService.tradePrecreate(builder);

        switch (result.getTradeStatus()) {
                case SUCCESS:
                    log.info("支付宝预下单成功: )");

                    AlipayTradePrecreateResponse response = result.getResponse();
                    dumpResponse(response);

                    //检查是否存在上传文件夹，如果不存在就赋予创建文件夹权限
                    File folder = new File(path);
                    if(!folder.exists()){
                        folder.setWritable(true);
                        folder.mkdirs();
                    }

                    // 需要修改为运行机器上的路径  C:\  /Users/sudo/Desktop
                    String qrpath = String.format(path+"/qr-%s.png",response.getOutTradeNo());

                    String qrFileName = String.format("/qr-%s.png",response.getOutTradeNo());

                    ZxingUtils.getQRCodeImge(response.getQrCode(),256,qrpath);

                    File targetFile = new File(path,qrFileName);

                    try {
                        //将生成的二维码上传到FTP服务器上
                        FTPUtil.uploadFile(Lists.newArrayList(targetFile));
                    } catch (IOException e) {
                       log.info("上传二维码异常",e);
                    }


                    log.info("qrpath:" + qrpath);
                    String qrUrl = PropertiesUtil.getProperty("ftp.server.http.prefix")+targetFile.getName();
                    resultMap.put("qrUrl",qrUrl);
                    return ResultData.createData(resultMap);

                case FAILED:
                    log.error("支付宝预下单失败!!!");
                    return ResultData.fail("支付宝预下单失败!!!");

                case UNKNOWN:
                    log.error("系统异常，预下单状态未知!!!");
                    return ResultData.fail("系统异常，预下单状态未知!!!");

                default:
                    log.error("不支持的交易状态，交易返回异常!!!");
                    return ResultData.fail("不支持的交易状态，交易返回异常!!!");
            }

    }
    // 简单打印应答
    private void dumpResponse(AlipayResponse response) {
        if (response != null) {
            log.info(String.format("code:%s, msg:%s", response.getCode(), response.getMsg()));
            if (StringUtils.isNotEmpty(response.getSubCode())) {
                log.info(String.format("subCode:%s, subMsg:%s", response.getSubCode(),
                        response.getSubMsg()));
            }
            log.info("body:" + response.getBody());
        }
    }


    //支付宝的回调通知接口
    public ResultData aliCallback(Map<String,String> params){

//        System.out.println("支付宝回调");
        Long orderNo = Long.parseLong(params.get("out_trade_no"));
        String tradeNo= params.get("trade_no");
        String tradeStatus = params.get("trade_status");

//        System.out.println("tradeStatus:"+tradeStatus);
        Order order = orderDao.selectByOrderNo(orderNo);

        if(order == null){
//            System.out.println("order == null");
            return  ResultData.fail("非该商场的订单，回调忽略");

        }
        if(order.getStatus() >= ConstUtil.OrderStatusEnum.PAID.getCode()){
//            System.out.println("支付宝重复调用");
            return ResultData.success("支付宝重复调用");
        }
        String su="TRADE_SUCCESS";
        if(su.equals(tradeStatus)){
//            System.out.println("开始更新为支付完成状态");
            order.setPaymentTime(DateTimeUtil.strToDate(params.get("gmt_payment")));
            order.setStatus(ConstUtil.OrderStatusEnum.PAID.getCode());

            orderDao.updateByPrimaryKeySelective(order);
        }

        PayInfo payInfo =new PayInfo();
        payInfo.setUserId(order.getUserId());
        payInfo.setOrderNo(order.getOrderNo());
        payInfo.setPayPlatform(ConstUtil.PayPlatformEnum.ALIPAY.getCode());
        payInfo.setPlatformNumber(tradeNo);
        payInfo.setPlatformStatus(tradeStatus);

        payInfoDao.insert(payInfo);
        return ResultData.success();
    }


//    @Override
//    public ResultData pay(Long orderNo, Integer userId, String path) {
//        return null;
//    }
//
//    @Override
//    public ResultData aliCallback(Map<String, String> params) {
//        return null;
//    }

    //查询订单状态的接口实现
    public ResultData queryOrderPayStatus(Integer userId,Long orderNo){
        Order order = orderDao.selectByUserIdAndOrderNo(userId,orderNo);
        if(order == null){
            return ResultData.fail("用户没有该订单");
        }
        if(order.getStatus()>=ConstUtil.OrderStatusEnum.PAID.getCode()){
            return ResultData.createData(order);
        }
            return ResultData.fail("查询当订单失败");
    }
}





